package com.adtec.base.cloud.server.gateway.filter.handler;

import com.adtec.base.cloud.server.gateway.filter.jpa.GlobalLog;
import com.adtec.base.cloud.server.gateway.filter.jpa.GlobalLogRepository;
import com.adtec.base.cloud.server.gateway.filter.utils.GetIpAddressUtil;
import com.adtec.base.cloud.server.gateway.jwt.model.JwtProperties;
import com.adtec.base.cloud.server.gateway.jwt.utils.JwtTokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.reactivestreams.Publisher;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.net.InetSocketAddress;
import java.net.URI;
import java.nio.charset.Charset;
import java.time.LocalDateTime;


@Slf4j
public class GlobalLogFilter implements GlobalFilter, Ordered {
    @Resource
    private JwtProperties jwtProperties;
    @Resource
    private JwtTokenUtil jwtTokenUtil;
    @Resource
    private GlobalLogRepository globalLogRepository;


    private int order;

    private static final String REQUEST_PREFIX = "\n--------------------------------- Request  Info -----------------------------";

    private static final String REQUEST_TAIL = "\n-----------------------------------------------------------------------------";

    private static final String RESPONSE_PREFIX = "\n--------------------------------- Response Info -----------------------------";

    private static final String RESPONSE_TAIL = "\n------------------------>>>";

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        long start = System.currentTimeMillis();

        GlobalLog globalLog = new GlobalLog();

        StringBuilder reqMsg = new StringBuilder();
        StringBuilder resMsg = new StringBuilder();
        // 获取请求信息
        ServerHttpRequest request = exchange.getRequest();
        String method = request.getMethodValue();
        URI uri = request.getURI();
        InetSocketAddress address = request.getRemoteAddress();
        GetIpAddressUtil getIpAddressUtil = new GetIpAddressUtil();
        String ipAddress = getIpAddressUtil.getIpAddress(request);

//        HttpHeaders headers = request.getHeaders();
//        // 获取请求body
//        Object cachedRequestBodyObject = exchange.getAttributeOrDefault(ConstantFilter.CACHED_REQUEST_BODY_OBJECT_KEY, null);
//        byte[] body = (byte[]) cachedRequestBodyObject;
//        String params = "";
//        if (body != null) {
//            params = new String(body);
//        }
//        // 获取请求query
//        Map queryMap = request.getQueryParams();
//        String query = JSON.toJSONString(queryMap);

        String jwtToken = request
                .getHeaders()
                .getFirst(jwtProperties.getHeader());
        String usernameFromToken = jwtTokenUtil.getUsernameFromToken(jwtToken);

        globalLog.setUrl(uri.getPath());
        globalLog.setMethod(method);
        globalLog.setUsername(usernameFromToken);
        globalLog.setAddress(ipAddress);
        globalLog.setPort(address.getPort());
        //TODO 这里可以将请求日志录入系统
        // 拼接请求日志
//        resMsg.append(REQUEST_PREFIX);
//        resMsg.append("\n url=").append(globalLog.getUrl());
//        resMsg.append("\n method=").append(globalLog.getMethod());
//        resMsg.append("\n username=").append(globalLog.getUsername());
//        resMsg.append("\n address=").append(globalLog.getAddress());
//        resMsg.append("\n port=").append(globalLog.getPort());
//        reqMsg.append(REQUEST_TAIL);
//        log.info(reqMsg.toString()); // 打印入参日志

        ServerHttpResponse response = exchange.getResponse();
        DataBufferFactory bufferFactory = response.bufferFactory();
        ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(response) {
            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                if (body instanceof Flux) {
                    Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
                    return super.writeWith(fluxBody.buffer().map(dataBuffers  -> {
                        DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
                        DataBuffer join = dataBufferFactory.join(dataBuffers);
                        byte[] content = new byte[join.readableByteCount()];
                        join.read(content);
                        //释放掉内存
                        DataBufferUtils.release(join);
                        String responseResult = new String(content, Charset.forName("UTF-8"));

                        //TODO 这里可以将响应日志录入系统
                        // 拼接请求日志

                        globalLog.setStatus(String.valueOf(this.getStatusCode()));
                        globalLog.setResponseResult(responseResult);

                        resMsg.append(REQUEST_PREFIX);
                        resMsg.append("\n url=").append(globalLog.getUrl());
                        resMsg.append("\n method=").append(globalLog.getMethod());
                        resMsg.append("\n username=").append(globalLog.getUsername());
                        resMsg.append("\n address=").append(globalLog.getAddress());
                        resMsg.append("\n port=").append(globalLog.getPort());
                        resMsg.append(RESPONSE_PREFIX);
                        resMsg.append("\n status=").append(globalLog.getStatus());
//                        resMsg.append("\n header=").append(this.getHeaders());
//                        resMsg.append("\n responseResult=").append(responseResult);
                        resMsg.append(RESPONSE_TAIL);

                        // 计算请求时间
                        long end = System.currentTimeMillis();

                        long time = end - start;
                        globalLog.setCostTime(time);
                        resMsg.append("耗时ms:").append(time);
                        log.info(resMsg.toString()); // 打印结果日志
                        globalLog.setCreateTime(LocalDateTime.now());
                        GlobalLog save = globalLogRepository.save(globalLog);
                        return bufferFactory.wrap(content);
                    }));
                }
                return super.writeWith(body);
            }
        };
        return chain.filter(exchange.mutate().response(decoratedResponse).build());
    }

    @Override
    public int getOrder() {
        return this.order;
    }

    public GlobalLogFilter(int order) {
        this.order = order;
    }
}

